// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_render_step_shadow_map.h"
#include "mk_render_device.h"
#include "mk_render_target.h"
#include "mk_engine.h"
#include "mk_error.h"
#include "mk_render_step_view_culling.h"
#include "mk_render_frame.h"
#include "mk_light_direction.h"
#include "mk_camera.h"
#include "mk_scene.h"

#include "mk_painter.h"

namespace MK3DE
{
	const char* CRenderStepShadow::RenderStepName = "__RenderStepShadowMap";

	CRenderStepShadow::CRenderStepShadow(CRenderFrame* renderFrame)
		: CRenderStep(renderFrame, CRenderStepShadow::RenderStepName)
	{
		_rtShadowMap = NULL;
		_shadowMapTextureSize = 1024;
	}

	CRenderStepShadow::~CRenderStepShadow()
	{
		CRenderDevice* rd = GetEngine()->GetRenderDevice();
		rd->DestroyRenderTarget(_rtShadowMap);
	}

	void CRenderStepShadow::SetShadowMapSize(DWORD size)
	{
		CRenderDevice* rd = GetEngine()->GetRenderDevice();
		if (_rtShadowMap && _shadowMapTextureSize != size)
			rd->DestroyRenderTarget(_rtShadowMap);

		_shadowMapTextureSize = size;
	}

	void CRenderStepShadow::Render()
	{
		CEngine* engine = GetEngine();
		CRenderDevice* renderDevice = engine->GetRenderDevice();

		if (!__CheckShadowMapRenderTarget())
			return;

		CRenderStepViewCulling* rsCulling = (CRenderStepViewCulling*)_renderFrame->GetRenderStepByName(CRenderStepViewCulling::RenderStepName);
		CCullingProcessor::CullingResult cullingResult = rsCulling->GetCullingResult();

		CCamera* pCamera = engine->GetCurrentCamera();
		CScene* pScene = rsCulling->GetScene();
		pScene->SetShadowMap(_rtShadowMap->GetRenderTargetTexture());
		CLightDirection* pLight = pScene->GetDirectionLight();
		D3DXVECTOR3 lightDir;
		pLight->GetDirection(lightDir);
		CShadowTSM* tsm = pScene->GetShadowMapCalculator();
		tsm->CalcTrapezoidalTransformation(pCamera->GetViewProjMatrix(), lightDir);

		renderDevice->SetRenderTarget(_rtShadowMap);
		renderDevice->Clear(TRUE, TRUE, TRUE, MK_COLOR_ARGB(255, 255, 255, 255), 1.0f, 0);

		for (int i = 0; i < (int)ERT_MAX; ++i)
		{
			std::vector<CEntity*>& vecEntity = cullingResult.vecEntity[i];
			std::vector<CEntity*>::iterator it = vecEntity.begin();
			while (it != vecEntity.end())
			{
				CEntity* entity = *it;
				entity->RenderShadow(tsm->GetMatrixLightViewProj(), tsm->GetMatrixTrapezoidal());

				++it;
			}
		}		
	}

	BOOL CRenderStepShadow::__CheckShadowMapRenderTarget()
	{
		if (_rtShadowMap)
			return TRUE;

		CEngine* engine = GetEngine();
		CRenderDevice* renderDevice = engine->GetRenderDevice();
		return renderDevice->CreateRenderTarget(_shadowMapTextureSize, _shadowMapTextureSize, PF_R32F, TRUE, _rtShadowMap);
	}
}